/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.webshop.backend.dbahif;


import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedList;

import org.webshop.backend.data.Product;


/**
 * 
 * @author Martin Haubenwallner
 * @coauthor Kevin Vodovnik
 * @coauthor Stefan Graf
 */
public class DBAccess {

    private static DBAccess INSTANCE;
    private DBAdvancedConnectionPool pool;

    private DBAccess() throws ClassNotFoundException {
        pool = DBAdvancedConnectionPool.getINSTANCE();
    }

    public static DBAccess getInstance() {
        if (INSTANCE == null) {
            synchronized (DBAccess.class) {
                if (INSTANCE == null) {
                    try {
                        INSTANCE = new DBAccess();
                    } catch (ClassNotFoundException e) {
                        throw new RuntimeException("Could not find jdbc driver class", e);
                    }
                }
            }
        }
        return INSTANCE;
    }

    /**
     * Returns all Products in a LinkedList
     * 
     * @return all Products
     * @throws SQLException
     */
    public LinkedList<Product> getProducts() throws SQLException {
        String key = "getProducts";
        LinkedList<Product> prodList = new LinkedList<Product>();
        AdvancedConnection con = pool.getConnection();
        if (con.getPreparedStatement(key) == null) {
            PreparedStatement pstm = con.getConnection().prepareStatement(
                "SELECT designation, url, price FROM product;");
            con.setPreparedStatement(key, pstm);
        }
        PreparedStatement statement = con.getPreparedStatement(key);
        ResultSet rs = statement.executeQuery();
        while (rs.next()) {
            String pizzaName = rs.getString("designation");
            String pizzaUrl = rs.getString("url");
            double pizzaPrice = rs.getDouble("price");
            Product product = new Product(pizzaUrl, pizzaName, pizzaPrice);
            prodList.add(product);
        }
        pool.releaseConnection(con);
        return prodList;

    }

    /**
     * Returns all Restaurants in a LinkedList
     * 
     * @return all Restaurants
     * @throws SQLException
     */
    public LinkedList<String> getRestaurants() throws SQLException {
        String key = "getRestaurants";
        LinkedList<String> restList = new LinkedList<String>();
        AdvancedConnection con = pool.getConnection();
        if (con.getPreparedStatement(key) == null) {
            PreparedStatement pstm = con.getConnection().prepareStatement("SELECT designation FROM restaurant;");
            con.setPreparedStatement(key, pstm);
        }
        PreparedStatement statement = con.getPreparedStatement(key);
        ResultSet rs = statement.executeQuery();
        while (rs.next()) {
            String restaurant = rs.getString("designation");
            restList.add(restaurant);
        }
        pool.releaseConnection(con);
        return restList;

    }

    /**
     * This method checks if an existing username was entered
     * 
     * @throws SQLException
     */
    public boolean doesUserExist(String username) throws SQLException {
        String key = "doesUserExist";
        String userNameQuery = "SELECT username FROM userlogin WHERE username = ?";
        AdvancedConnection con = pool.getConnection();
        if (con.getPreparedStatement(key) == null) {
            con.setPreparedStatement(key, con.getConnection().prepareStatement(userNameQuery));
        }
        PreparedStatement pStat = con.getPreparedStatement(key);
        pStat.setString(1, username);
        ResultSet rs = pStat.executeQuery();
        boolean found = rs.next();
        pool.releaseConnection(con);
        return found;
    }

    /**
     * This method checks if an existing password was entered
     * 
     * @throws NoSuchAlgorithmException
     * @throws SQLException
     */
    public boolean checkPassword(String username, String password) throws SQLException, NoSuchAlgorithmException {
        String key = "checkPassword";
        String userPasswordQuery = "SELECT username FROM userlogin WHERE username = ? AND password =?";
        AdvancedConnection con = pool.getConnection();
        if (con.getPreparedStatement(key) == null) {
            con.setPreparedStatement(key, con.getConnection().prepareStatement(userPasswordQuery));
        }
        PreparedStatement pStat = con.getPreparedStatement(key);
        pStat.setString(1, username);
        MessageDigest md = MessageDigest.getInstance("SHA-1");
        md.update(password.getBytes());
        byte[] hashCode = md.digest();
        String passwdAsHexString = convertToHexString(hashCode);
        pStat.setString(2, passwdAsHexString);
        ResultSet rs = pStat.executeQuery();
        boolean found = rs.next();
        pool.releaseConnection(con);
        return found;
    }

    /**
     * This method inserts a new user into the DB
     * 
     */
    public synchronized boolean register(String username, String password)
            throws NoSuchAlgorithmException, SQLException {
        // Encrypt password:
        String key = "register";
        String registerStmt = "TODO";
        MessageDigest md = MessageDigest.getInstance("SHA-1");
        md.update(password.getBytes());
        byte[] hashCode = md.digest();
        String passwdAsHexString = convertToHexString(hashCode);
        System.out.println(passwdAsHexString);
        AdvancedConnection con = pool.getConnection();
        if (con.getPreparedStatement(key) == null) {
            con.setPreparedStatement(key, con.getConnection().prepareStatement(registerStmt));
        }
        PreparedStatement pStat = con.getPreparedStatement(key);
        pStat.setString(1, username);
        pStat.setString(2, passwdAsHexString);
        int lines = pStat.executeUpdate();
        pool.releaseConnection(con);
        return lines == 1;
    }

    /**
     * This method converts the password into a hex string
     */
    public String convertToHexString(byte[] hashCode) {
        String ret = "";
        for (byte b : hashCode) {
            int value = (b & 0x7F) + (b < 0 ? 128 : 0);
            ret += (value < 16 ? "0" : "");
            ret += Integer.toHexString(value).toUpperCase();
        }
        return ret;
    }
}
